package com.situ.mall.service.impl;

import com.situ.mall.mapper.ProductMapper;
import com.situ.mall.pojo.Product;
import com.situ.mall.service.IProductService;
import com.situ.mall.util.JSONResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.support.ResourceScriptSource;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

@Service
public class ProductServiceImpl implements IProductService {
    @Autowired
    private ProductMapper productMapper;
    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public Product selectById(Integer id) {
        return productMapper.selectByPrimaryKey(id);
    }

    @Override
    public List<Product> selectListByCategoryId(Integer id) {
        return productMapper.selectListByCategoryId(id);
    }

    //@Override
    public JSONResult secondKill1(Integer productId, Integer userId) {
        synchronized (this) {
            // userId随机生成，代表不同的用户
            userId = new Random().nextInt(50000);
            //System.out.println("userId:" + userId);

            // 拼接key
            // 1.库存key   sk:26:qt 10
            String quantityKey = "sk:" + productId + ":qt";
            // 2.秒杀成功用户的可以 set集合  sk:26:user
            String userKey = "sk:" + productId + ":user";

            // 获取库存，如果库存为null，代表秒杀还没有开始
            Integer quantity = (Integer) redisTemplate.opsForValue().get(quantityKey);
            if (quantity == null) {
                System.out.println("秒杀还没有开始，请等候");
                return JSONResult.error("秒杀还没有开始，请等候");
            }
            // 判断用户是不是重复秒杀
            if (redisTemplate.opsForSet().isMember(userKey, userId)) {
                System.out.println("已经秒杀成功，不能重复秒杀");
                return JSONResult.error("已经秒杀成功，不能重复秒杀");
            }
            //判断秒杀商品数量，如果<=0代表秒杀结束了
          /* if (quantity <= 0) {
               System.out.println("秒杀已经结束了");
               return JSONResult.error("秒杀已经结束了");
           }*/

            if (quantity >= 1) {
                // 秒杀过程
                redisTemplate.opsForValue().decrement(quantityKey, 1);
                redisTemplate.opsForSet().add(userKey, userId);
            } else {
                System.out.println("秒杀已经结束了");
                return JSONResult.error("秒杀已经结束了");
            }
        }
        // TODO：根据userId和productId生成订单
        System.out.println("秒杀成功");
        return JSONResult.ok("秒杀成功");
    }

    //@Override
    public JSONResult secondKill2(Integer productId, Integer userId) {
        // userId随机生成，代表不同的用户
        userId = new Random().nextInt(50000);
        //System.out.println("userId:" + userId);

        // 拼接key
        // 1.库存key   sk:26:qt 10
        String quantityKey = "sk:" + productId + ":qt";
        // 2.秒杀成功用户的可以 set集合  sk:26:user
        String userKey = "sk:" + productId + ":user";

        // 秒杀过程、使用事物
        Integer finalUserId = userId;
        Object jsonResult = redisTemplate.execute(new SessionCallback<JSONResult>() {
            @Override
            public JSONResult execute(RedisOperations operations) throws DataAccessException {
                operations.watch(quantityKey);
                // Multi之前的代码可以不必放在SessionCallback中一并执行，
                // 但是watch指令和事物指令，必须在同一个SessionCallback中。

                // 获取库存，如果库存为null，代表秒杀还没有开始
                Integer quantity = (Integer) operations.opsForValue().get(quantityKey);
                if (quantity == null) {
                    System.out.println("秒杀还没有开始，请等候");
                    return JSONResult.error("秒杀还没有开始，请等候");
                }
                // 判断用户是不是重复秒杀
                if (operations.opsForSet().isMember(userKey, finalUserId)) {
                    System.out.println("已经秒杀成功，不能重复秒杀");
                    return JSONResult.error("已经秒杀成功，不能重复秒杀");
                }
                //判断秒杀商品数量，如果<=0代表秒杀结束了
                if (quantity <= 0) {
                    System.out.println("秒杀已经结束了");
                    return JSONResult.error("秒杀已经结束了");
                }

                operations.multi();
                // 秒杀过程
                operations.opsForValue().decrement(quantityKey, 1);
                operations.opsForSet().add(userKey, finalUserId);
                List<Object> results = operations.exec();
                if (results == null || results.size() == 0) {
                    return  JSONResult.error("秒杀失败");
                } else {
                    return JSONResult.ok("秒杀成功");
                }
            }
        });
        // TODO：根据userId和productId生成订单
        return (JSONResult) jsonResult;

    }

    @Override
    public JSONResult secondKill(Integer productId, Integer userId) {
        // userId随机生成，代表不同的用户
        userId = new Random().nextInt(50000);
        //System.out.println("userId:" + userId);
        // 1.库存key   sk:26:qt 10
        String quantityKey = "sk:" + productId + ":qt";
        // 2.秒杀成功用户的可以 set集合  sk:26:user
        String userKey = "sk:" + productId + ":user";

        //Redis中的Integer对应Java中的Long。
        DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
        redisScript.setResultType(Long.class);
        redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("redis/second_kill.lua")));
        List<String> keyList = new ArrayList<>();
        keyList.add(quantityKey);
        keyList.add(userKey);
        Long result = (Long) redisTemplate.execute(redisScript, keyList, userId + "");

        if (result == 3) {
            System.out.println("您已经参与过秒杀,不能重复参加");
            return JSONResult.error("您已经参与过秒杀,不能重复参加");
        } else if (result == 2) {
            System.out.println("秒杀已经结束");
            return JSONResult.error("秒杀已经结束");
        } else if (result == 1) {
            System.out.println("秒杀成功");
            return JSONResult.ok("秒杀成功");
        }
        // TODO：根据userId和productId生成订单
        return JSONResult.error("秒杀成功");

    }

}
